Stay Hungry,Stay Foolish!

python attribute creation

attribute

https://medium.com/swlh/attributes-in-python-6-concepts-to-know-1db6562057b1

OOP中对象带有的参数,叫做 field attribute property

python中把这种参数叫做 attribute

In the modern programming world, object-oriented programming (OOP) languages have played an evolutionary role in changing the design and implementation patterns in software development. As a critical member of the OOP family, Python has gradually gained popularity in the last 10 years or so. Like other OOP languages, Python operates its data around a vast diversity of objects, including modules, classes, and functions.

If you have any coding experience in any OOP language, you should probably know that all objects have their internal characteristics data called fields, attributes, or properties. In Python, these object-bound characteristics data are commonly known as attributes. In this article, I would like to talk about them, specifically in the context of a custom class.

 

class attribute

类中定义的属性。

定义形式在 class的下一级。

这种属性为此class拥有, 为所有此class的instance共享。

 

>>> class Dog:
...     genus = "Canis"
...     family = "Canidae"
...
>>> Dog.genus
'Canis'
>>> Dog.family
'Canidae'
>>> dir(Dog)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', 
 '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', 
 '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
 '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 
 'family', 'genus']

 

如上python使用 dir 函数来查看类的 属性列表。

As shown above, we declared a class called Dog. Because all dogs belong to the Canis genus and Canidae family (Wikipedia), we created two class attributes named genus and family to store these two pieces of information. As you can see, we could directly use the class to access these attributes. We can use the introspection function dir to show the list of the Dog’s attributes, which include family and genus.

Instance Attributes

实例的属性,定义在 __init__ 函数中, 依附于self对象, self就是实例对象。

这些属性为本实例独享, 每生成一个实例则这些属性都会被创建, 所以一些常量,和所有实例共享内容,都应该定义为 class属性。

With custom classes, we can also set attributes to instance objects. These attributes are known as instance attributes, which means that they are instance-specific data. Let’s continue with the Dog class.

 

In the above code, we defined the __init__ function, which will serve as the construction method to create a new Dog instance. The first argument self refers to the instance that we’re creating. During the instantiation (i.e., creating the new instance), we will assign the breed and name information to the new instance object, and these attributes will become part of the instance’s characteristics, as shown below.

 

>>> class Dog:
...     genus = "Canis"
...     family = "Canidae"
...
...     def __init__(self, breed, name):
...         self.breed = breed
...         self.name = name
...
>>> dog = Dog("Rottweiler", "Ada")
>>> dog.name
'Ada'
>>> dog.breed
'Rottweiler'

 

Functions As Attributes

属性不仅仅是一般变量, 还可以是函数。

 

In Python, everything is an object, and previously, I already mentioned that classes are objects. Moreover, functions are Python objects. Within a class, we can define functions, which are commonly referred to as methods. Depending on how the functions are used, we can further categorize them as class methods, static methods, and instance methods. It’s not essential here to understand these differences (see my previous articles: this and that, if you want to learn them).

Although some OOP languages treat attributes (or properties) and functions as different entities, Python considers these methods (functions) as attributes of the class — not very different as the class attributes that we defined earlier. Let’s just update the Dog class with all three kinds of methods as mentioned above: class, static, and instance methods, as shown below.

 

>>> class Dog:
...     genus = "Canis"
...     family = "Canidae"
...
...     def __init__(self, breed, name):
...         self.breed = breed
...         self.name = name
...
...     @classmethod
...     def from_tag(cls, tag_info):
...         breed = tag_info["breed"]
...         name = tag_info["name"]
...         return cls(breed, name)
...
...     @staticmethod
...     def can_bark():
...         print("Yes. All dogs can bark.")
...
...     def bark(self):
...         print("The dog is barking.")

 

>>> dir(Dog)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', 
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', 
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 
'bark', 'can_bark', 'family', 'from_tag', 'genus']

 

Private Attributes

私有属性归于本实例内部使用, 不能被实例调用者使用。

私有属性,命名以双下划线开头, 尾部不带有下划线。不与 魔法函数冲突。

If you have any experience in OOP, you shouldn’t be unfamiliar with the existence of access modifiers, such as public, private, and protected. These modifiers restrict the scope of where the modified attributes and functions can be accessed. However, you rarely hear such a discussion in Python. Practically, all Python attributes are public, if we borrow the terminology in the OOP world. As shown above, the class and instance attributes are all freely accessible where these classes and instances are accessible. Thus, strictly speaking, there are no real private or protected attributes (to be discussed next) in Python. We’re just using these terms analogously, such that it’ll be easier for programmers coming from other OOP background to appreciate related coding conventions (yes, just a convention, not reinforced as real access control).

Let’s first talk about how we can define a “private” attribute in Python. The convention is to name those attributes with two leading underscores and no more than one trailing underscore. Consider the following example of the updated Dog class — for simplicity, we omit other attributes that we defined previously.

 

>>> class Dog:
...     def __init__(self, breed, name):
...         self.breed = breed
...         self.name = name
...         self.__tag = f"{name} | {breed}"
... 
>>> dog = Dog("Rottweiler", "Ada")
>>> dog.name
'Ada'
>>> dog.__tag
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Dog' object has no attribute '__tag'

 

实际上python没有私有属性,只不过给这种属性的名称做了变化。

After the above update, the Dog instances will have a private attribute called tag, as indicated by its name. The instance object could still access its other attributes (e.g., name) as before. However, the instance couldn’t access the private attribute __tag as we may be expecting. Indeed, such a restriction of accessing these attributes is exactly how they can be called “private” attributes. But how did it happen, under the hood? After all, I previously mentioned that all Python attributes are public by default. The following shows you how Python implements “private” attributes.

 

>>> dog.__dict__
{'breed': 'Rottweiler', 'name': 'Ada', '_Dog__tag': 'Ada | Rottweiler'}
>>> dog._Dog__tag
'Ada | Rottweiler'

 

Protected Attributes

保护属性, 为前缀只有一个下划线的属性。

_xx 的属性名没有被变化,可以被直接引用到。

意思为,可以使用,但是不鼓励。

 

In the last section, we talked about private attributes, but how about protected attributes? The counterparts of protected attributes in Python are attributes whose names have only one underscore. Unlike the double underscores which will result in mangling, the single underscore prefix doesn’t change how Python interpreter handles these attributes — It’s merely a convention in the Python programming world to denote that they (i.e., the coder) doesn’t want you to access these attributes. However, again, if you insist on accessing them, you can still do that. Let’s see the code below.

>>> class Dog:
...     def __init__(self, breed, name):
...         self.breed = breed
...         self.name = name
...         self.__tag = f"{name} | {breed}"
...         self._nickname = name[0]

 

We updated the class Dog by creating an instance attribute called _nickname. As indicated by its name using an underscore prefix, it is considered as a “protected” attribute by convention. We can still access these protected attributes as other “public” attributes, but some IDEs or Python editors will not provide prompts (e.g., autocompletion hints) for these non-public attributes. See the screenshot for these examples using the Jupyter Notebook.

No Auto-completion Suggestions for Non-Public Attributes

If we work with modules instead of classes as we’re doing here, when we import the module using from the_module import *, the names with the underscore prefix won’t be imported, providing a mechanism for restricting access to these “protected” attributes.

 

Properties

property跟属性还是有差异的

property是属性的子集, 其仅仅是函数。

property提供的注解, 提供了对私有属性的读取控制, 和 写保护。

 

Some OOP languages use attributes and properties interchangeably, but they are different concepts in Python. As discussed, attributes in Python are a broad concept that can include different kinds of attributes and functions. However, properties in Python are essentially functions that are decorated with the @property decorator. The decorated function will provide the callers with easier access to these properties. They can often be used together with the protected attributes. Let’s see an example.

 

>>> class Dog:
...     # Same __init__ method
...     @property
...     def nickname(self):
...         return self._nickname
...
...     @nickname.setter
...     def nickname(self, new_nickname):
...         self._nickname = new_nickname
...

 

属性寻找与继承

属性寻找,遵循从下到上原则。

先在实例上自身找, 找不到寻找其上级class对应的属性, 在上级class找不到,则继续上上找, 知道找到object

 

 

 

 

 

 

属性动态添加

https://stackoverflow.com/questions/65547821/how-to-add-attribute-to-class-in-python

属性动态添加有两种方法(对class或者实例,都可以)

一, 使用setattr赋值

二,直接赋值, 例如 x.d = 1

1
 
 

There're two ways of setting an attribute to your class;

First, by using setattr(class, variable, value)

Code Syntax

setattr(A,'c', 'c')
print(dir(A))

OUTPUT

You can see the structure of the class A within attributes

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', 
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', 
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'__weakref__', 'a', 'b', 'c']

[Program finished]

Second, you can do it simply by assigning the variable

Code Syntax

A.d = 'd'
print(dir(A))

OUTPUT

You can see the structure of the class A within attributes

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', 
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', 
'__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'__weakref__', 'a', 'b', 'c', 'd']

[Program finished]

 

缺点:

对于不存在的属性访问,会抛出异常。

这往往不是我们希望的。

 

Property解决此问题

很多库使用了 property装饰器, 来解决此问题。

但是使用这种方法需要注意, 不能使用 hasattr 再进行属性存在性的判断, 因为这个方法会导致属性一直存在。

https://www.datacamp.com/tutorial/property-getters-setters#:~:text=%40property%20is%20used%20to%20get%20the%20value%20of,We%20have%20to%20use%20it%20as%20a%20setter.?msclkid=16516808cf7311ec83af64cf4afa2afc

class Property:

    def __init__(self, var):
        ## initializing the attribute
        self.a = var

    @property
    def a(self):
        return self.__a

    ## the attribute name and the method name must be same which is used to set the value for the attribute
    @a.setter
    def a(self, var):
        if var > 0 and var % 2 == 0:
            self.__a = var
        else:
            self.__a = 2

 

property() 函数

https://www.geeksforgeeks.org/getter-and-setter-in-python/?msclkid=c78369f8cf8911eca494095d9ff7cc41

 

Using property() function to achieve getters and setters behaviour

In Python property()is a built-in function that creates and returns a property object. A property object has three methods, getter(), setter(), and delete(). property() function in Python has four arguments property(fget, fset, fdel, doc), fget is a function for retrieving an attribute value. fset is a function for setting an attribute value. fdel is a function for deleting an attribute value. doc creates a docstring for attribute. A property object has three methods, getter(), setter(), and delete() to specify fget, fset and fdel individually. For Example

# Python program showing a
# use of property() function

class Geeks:
    def __init__(self):
        self._age = 0
    
    # function to get value of _age
    def get_age(self):
        print("getter method called")
        return self._age
    
    # function to set value of _age
    def set_age(self, a):
        print("setter method called")
        self._age = a

    # function to delete _age attribute
    def del_age(self):
        del self._age
    
    age = property(get_age, set_age, del_age)

mark = Geeks()

mark.age = 10

print(mark.age)

 

posted @ 2022-05-10 00:01  lightsong  阅读(95)  评论(0)    收藏  举报
千山鸟飞绝,万径人踪灭