python - 如何创建类属性?

在python中,我可以使用@classmethod装饰器向类添加方法。 是否有类似的装饰器向类中添加属性? 我可以更好地展示我在说什么。

class Example(object):

the_I = 10

def __init__( self ):

self.an_i = 20

@property

def i( self ):

return self.an_i

def inc_i( self ):

self.an_i += 1

# is this even possible?

@classproperty

def I( cls ):

return cls.the_I

@classmethod

def inc_I( cls ):

cls.the_I += 1

e = Example()

assert e.i == 20

e.inc_i()

assert e.i == 21

assert Example.I == 10

Example.inc_I()

assert Example.I == 11

我上面使用的语法是可能的还是需要更多的东西?

我想要类属性的原因是我可以延迟加载类属性,这似乎足够合理。

7个解决方案

66 votes

这是我将如何做到这一点:

class ClassPropertyDescriptor(object):

def __init__(self, fget, fset=None):

self.fget = fget

self.fset = fset

def __get__(self, obj, klass=None):

if klass is None:

klass = type(obj)

return self.fget.__get__(obj, klass)()

def __set__(self, obj, value):

if not self.fset:

raise AttributeError("can't set attribute")

type_ = type(obj)

return self.fset.__get__(obj, type_)(value)

def setter(self, func):

if not isinstance(func, (classmethod, staticmethod)):

func = classmethod(func)

self.fset = func

return self

def classproperty(func):

if not isinstance(func, (classmethod, staticmethod)):

func = classmethod(func)

return ClassPropertyDescriptor(func)

class Bar(object):

_bar = 1

@classproperty

def bar(cls):

return cls._bar

@bar.setter

def bar(cls, value):

cls._bar = value

# test instance instantiation

foo = Bar()

assert foo.bar == 1

baz = Bar()

assert baz.bar == 1

# test static variable

baz.bar = 5

assert foo.bar == 5

# test setting variable on the class

Bar.bar = 50

assert baz.bar == 50

assert foo.bar == 50

因为我们打电话,所以当我们打电话Bar.bar时,二传手工作不起作用TypeOfBar.bar.__set__,这不是Bar.bar.__set__。

添加元类定义解决了这个问题:

class ClassPropertyMetaClass(type):

def __setattr__(self, key, value):

if key in self.__dict__:

obj = self.__dict__.get(key)

if obj and type(obj) is ClassPropertyDescriptor:

return obj.__set__(self, value)

return super(ClassPropertyMetaClass, self).__setattr__(key, value)

# and update class define:

# class Bar(object):

# __metaclass__ = ClassPropertyMetaClass

# _bar = 1

# and update ClassPropertyDescriptor.__set__

# def __set__(self, obj, value):

# if not self.fset:

# raise AttributeError("can't set attribute")

# if inspect.isclass(obj):

# type_ = obj

# obj = None

# else:

# type_ = type(obj)

# return self.fset.__get__(obj, type_)(value)

现在一切都会好的。

Mahmoud Abdelkader answered 2019-08-04T11:11:55Z

31 votes

如果您按如下方式定义e.I = 20,那么您的示例将完全按照您的请求工作。

class classproperty(object):

def __init__(self, f):

self.f = f

def __get__(self, obj, owner):

return self.f(owner)

需要注意的是,您不能将其用于可写属性。 而e.I = 20将提升AttributeError,Example.I = 20将覆盖属性对象本身。

jchl answered 2019-08-04T11:12:30Z

24 votes

我想你可以用元类做到这一点。 因为元类可以像类的类(如果有意义的话)。 我知道你可以为元类分配一个class MyClass(metaclass=MetaClass):方法来覆盖调用类__metaclass__.我想知道在元类上使用property装饰器是否操作类似。 (我之前没试过,但现在我好奇......)

[更新:]

哇,确实有效:

class MetaClass(type):

def getfoo(self):

return self._foo

foo = property(getfoo)

@property

def bar(self):

return self._bar

class MyClass(object):

__metaclass__ = MetaClass

_foo = 'abc'

_bar = 'def'

print MyClass.foo

print MyClass.bar

注意:这是在Python 2.7中。 Python 3+使用不同的技术来声明元类。 使用:class MyClass(metaclass=MetaClass):,删除__metaclass__,其余部分相同。

dappawit answered 2019-08-04T11:13:19Z

17 votes

[基于python 3.4编写的答案; 元类语法在2中有所不同,但我认为该技术仍然有效]

你可以用元类来做这件事......大多数情况下。 Dappawit几乎可以工作,但我认为它有一个缺陷:

class MetaFoo(type):

@property

def thingy(cls):

return cls._thingy

class Foo(object, metaclass=MetaFoo):

_thingy = 23

这会让你获得Foo的一个类属性,但是有一个问题......

print("Foo.thingy is {}".format(Foo.thingy))

# Foo.thingy is 23

# Yay, the classmethod-property is working as intended!

foo = Foo()

if hasattr(foo, "thingy"):

print("Foo().thingy is {}".format(foo.thingy))

else:

print("Foo instance has no attribute 'thingy'")

# Foo instance has no attribute 'thingy'

# Wha....?

这到底是怎么回事? 为什么我不能从实例到达类属性?

在找到我认为的答案之前,我在这方面打了很长时间。 Python @properties是描述符的子集,并且从描述符文档(强调我的):

属性访问的默认行为是获取,设置或删除   来自对象字典的属性。 例如,a.x具有查找链   从a.__dict__['x']开始,然后是type(a).__dict__['x'],并继续   通过基类Foo().thingy不包括元类。

因此,方法解析顺序不包括我们的类属性(或元类中定义的任何其他内容)。 可以使内置属性装饰器的子类具有不同的行为,但是(引用需要)我已经得到了开发人员有一个很好的理由(我不明白)这样做的印象。

这并不意味着我们运气不好; 我们可以很好地访问类本身的属性......我们可以从实例中获取Foo().thingy的类,我们可以使用它来生成@property调度程序:

class Foo(object, metaclass=MetaFoo):

_thingy = 23

@property

def thingy(self):

return type(self).thingy

现在Foo().thingy适用于类和实例! 如果派生类替换了它的基础_thingy(这是最初让我进行此搜索的用例),它也将继续做正确的事情。

这对我来说并不是100%满足 - 不得不在元类和对象类中进行设置,感觉它违反了DRY原则。 但后者只是一个单线调度员; 我现在对它很好,如果你真的想要的话,你可以将它压缩成lambda或者其他东西。

Andrew answered 2019-08-04T11:14:58Z

4 votes

据我所知,没有创建新的元类,就没有办法为类属性编写setter。

我发现以下方法有效。 使用所需的所有类属性和设置器定义元类。 IE,我想要一个title属性的类,带有setter。 这是我写的:

class TitleMeta(type):

@property

def title(self):

return getattr(self, '_title', 'Default Title')

@title.setter

def title(self, title):

self._title = title

# Do whatever else you want when the title is set...

现在正常创建您想要的实际类,除非它使用您在上面创建的元类。

# Python 2 style:

class ClassWithTitle(object):

__metaclass__ = TitleMeta

# The rest of your class definition...

# Python 3 style:

class ClassWithTitle(object, metaclass = TitleMeta):

# Your class definition...

如上所述,如果我们只在单个类上使用它,那么定义这个元类有点奇怪。 在这种情况下,如果您使用的是Python 2样式,则可以在类主体中实际定义元类。 这样它就没有在模块范围内定义。

ArtOfWarfare answered 2019-08-04T11:15:52Z

1 votes

如果您只需要延迟加载,那么您可以使用类初始化方法。

EXAMPLE_SET = False

class Example(object):

@classmethod

def initclass(cls):

global EXAMPLE_SET

if EXAMPLE_SET: return

cls.the_I = 'ok'

EXAMPLE_SET = True

def __init__( self ):

Example.initclass()

self.an_i = 20

try:

print Example.the_I

except AttributeError:

print 'ok class not "loaded"'

foo = Example()

print foo.the_I

print Example.the_I

但是元类方法看起来更清晰,并且具有更可预测的行为。

也许您正在寻找的是Singleton设计模式。 关于在Python中实现共享状态有一个很好的SO QA。

Apalala answered 2019-08-04T11:16:35Z

0 votes

我碰巧提出了一个非常类似于@Andrew的解决方案,只有DRY

class MetaFoo(type):

def __new__(mc1, name, bases, nmspc):

nmspc.update({'thingy': MetaFoo.thingy})

return super(MetaFoo, mc1).__new__(mc1, name, bases, nmspc)

@property

def thingy(cls):

if not inspect.isclass(cls):

cls = type(cls)

return cls._thingy

@thingy.setter

def thingy(cls, value):

if not inspect.isclass(cls):

cls = type(cls)

cls._thingy = value

class Foo(metaclass=MetaFoo):

_thingy = 23

class Bar(Foo)

_thingy = 12

这是所有答案中最好的:

“metaproperty”被添加到类中,因此它仍然是实例的属性

不需要在任何类中重新定义thingy

该属性作为实例和类的“类属性”

您可以灵活地自定义_thingy的继承方式

在我的情况下,我实际上为每个孩子定制了_thingy,而没有在每个类中定义它(并且没有默认值):

def __new__(mc1, name, bases, nmspc):

nmspc.update({'thingy': MetaFoo.services, '_thingy': None})

return super(MetaFoo, mc1).__new__(mc1, name, bases, nmspc)

Andy answered 2019-08-04T11:17:49Z

python在子类中添加新的属性_python - 如何创建类属性?相关推荐

  1. python在子类中添加新的属性_pycharm实现在子类中添加一个父类没有的属性

    我就废话不多说了,还是直接看代码吧! class Car(): """一次模拟汽车的简单尝试""" def __init__(self, m ...

  2. python动态创建对象属性_python – 动态创建类属性

    你可以在没有使用装饰器的元类的情况下完成它.这种方式有点清楚IMO: def apply_defaults(cls): defaults = { 'default_value1':True, 'def ...

  3. 在Carla中添加新的地图

    参考链接: https://carla.readthedocs.io/en/latest/tuto_A_add_map/ 在Carla中添加新的地图 使用者可以创建自己的地图并且在carla中使用地图 ...

  4. js 对象中添加新属性

    js 对象中添加新属性 对象数组添加新属性 同名属性会被覆盖,相同属性会去重

  5. 在VirtualBox中的Ubuntu中添加新硬盘

    2019独角兽企业重金招聘Python工程师标准>>> 在VirtualBox中的Ubuntu中添加新硬盘 VitrualBox是不允许更改重置硬盘大小的,所以当硬盘不足时,只能添加 ...

  6. Sharepoint学习笔记—Ribbon系列-- 2. 在Ribbon中添加新Tab

    有了上面的基础,我们来看看如何向Sharepoint网站的Ribbon中添加我们定义的Tab. 直接进入操作步骤 一.创建 SharePoint 项目 要添加新选项卡,应首先创建一个空白 ShareP ...

  7. 在NS3中添加新的VANET模块

    本文主要参考http://blog.csdn.net/barcodegun/article/details/6898193此博主的学习笔记,但由于版本过老,很多小细节不适用于ns-3.26,特来更新自 ...

  8. Python 在子类中调用父类方法详解(单继承、多层继承、多重继承)

    Python 在子类中调用父类方法详解(单继承.多层继承.多重继承)   by:授客 QQ:1033553122   测试环境: win7 64位 Python版本:Python 3.3.5 代码实践 ...

  9. Sharepoint学习笔记—Ribbon系列-- 5. 在Ribbon中添加新控件(针对用户自定义Tab)

    前面我们实现了向用户自定义的Tab中添加新的Group,并向其中创建了两个Button按钮.这里我们看看如何向这个已经创建好的Group中再另外添加新的Button控件(当然,你可以添加其它控件,实现 ...

最新文章

  1. Faiss教程:索引(2)
  2. 【10.8】每日NLP学术论文推荐
  3. static使用之静态变量
  4. 【三维路径规划】基于matlab RRT算法无人机三维路径规划【含Matlab源码 155期】
  5. 计算机科学导论第四版ppt,计算机科学导论课件.ppt
  6. 递归算法和经典递归例子
  7. 思科2811路由器采购回来首次配置
  8. 斐讯K2路由器刷潘多拉(解决固件非法问题)(连接校园网锐捷)
  9. 新版edge浏览器没有internet选项怎么办?
  10. Android/IOS/Web跳转第三方QQ指定QQ号的聊天框,实现陌生人聊天
  11. 一语道破 到底什么是知识产权?
  12. 腾讯云直播 延迟排查
  13. 2019年的元旦还是一个人?邮箱163陪你如何?
  14. java论文答辩老师会问什么,毕业论文答辩老师一般会问什么问题
  15. 分布式系统的特点及问题
  16. 使用restormer网络做2022年中兴捧月图像去噪
  17. C++ primer 第五版 练习题记录
  18. c语言怎么算除法算式,随机算式的除法如果答案是无限循环小数,怎么加精度?...
  19. Java语言的优雅停机 - 第308篇
  20. 实验第五节——channel相关操作

热门文章

  1. 德国工业4.0 相关标准 免费下载
  2. 如何快速提取文件名放在一个excel表里?
  3. 2009年国庆再回桂林(有图片)
  4. 好压zip格式的文件,然后用WinRAR解压缩该文件报错
  5. 怎么关闭win7计算机一键还原系统,Windows7系统怎么一键还原【图文教程】
  6. 计算机中usb指啥,usb接口指的是_通俗关于USB接口的知识
  7. BS架构和CS架构 + Tomcat安装及配置
  8. 解读少儿编程教师的日常工作
  9. 学计算机和美发哪个好,今天跟大家分享一下我选择美发行业的原因
  10. PHP 开发 ThinkPHP6 框架学习 一