• 9. A Pythonic Object


    • Thanks to the Python data model, your user-defined types can behave as naturally as the built-in types. And this can be accomplished without inheritance, in the spirit of duck typing: you just implement the methods needed for your objects to behave as expected.

    1. Classmethod Versus Staticmethod

    class Test:
    	@staticmethod
    	def f1(*args):
    		print args
    	# define a method that operates on the class and not on instances.
    	@classmethod
    	def f2(*args):  # cls = args[0]
    		print args
    
    t = Test()
    t.f1('1')  # ('1',)
    t.f2('1')  # (<class __main__.Test at 0x10afeca78>, '1')
    
    # 1. Classmethod's most common use is for alternative constructors.
    # 2. In essence, a static method is just like a plain function that
    # happens to live in a class body, instead of being defined at the
    # module level.
    

    2. Formatted Displays

    brl = 1/2.43
    print(brl)  # 0.4115226337448559
    print(format(brl, '0.4f'))  # 0.4115
    print('BRL = {rate:0.2f}'.format(rate=brl))  # BRL = 0.41
    print(format(42, 'b'))  # 101010
    print(format(2/3, '.1%'))  # 66.7%
    from datetime import datetime
    now = datetime.now()
    print("It's {:%I:%M %p}".format(now))  # It's 10:59 AM
    
    class A:
    	def __init__(self, a1, a2):
    		self.a1 = a1
    		self.a2 = a2
    	def __iter__(self):
    		return (i for i in (self.a1, self.a2))
    	def __format__(self, fmt_spec=''):
    		if fmt_spec is '':
    			fmt_spec = '({}, {})'
    		return fmt_spec.format(*self)
    
    a = A(3, 4)
    print(format(a))  # (3, 4)
    print(format(a, '-->{}, {}<--'))  # -->3, 4<--
    
    # 1. A format string such as '{0.mass: 5.3e}' actually uses two
    # separate notations. The '0.mass' to the left of the colon is the
    # field_name part of the replacement field syntax; the '5.3e' after
    # the colon is the formatting specifier.
    # 2. A few built-in types have their own presentation codes.
    # 3. If a class has no __format__, format(obj) returns str(obj)
    

    3. Private and “Protected” Attributes in Python

    • Python stores the attributes with two leading underscores in the instance __dict__, prefixed with a leading underscore and the class name. (Dog + __mood --> _Dog__mood)
    • Name mangling is about safety, not security: it’s designed to prevent accidental access and not intentional wrongdoing.
    • But if you are doing 'v1._Vector__x = 7' in production code, you can’t complain if something blows up.
    • Attributes with a single _ prefix are called “protected” in some corners of the Python documentation.9 The practice of “protecting” attributes by convention with the form self._x is widespread, but calling that a “protected” attribute is not so common. Some even call that a “private” attribute.

    4. Object Representations

    from array import array
    import math
    
    class Vector2d:
    	typecode = 'd'
    	def __init__(self, x, y):
    		self.__x = float(x)
    		self.__y = float(y)
    	@property
    	def x(self):
    		return self.__x
    	@property
    	def y(self):
    		return self.__y
    	def __iter__(self):
    		return (i for i in (self.x, self.y))  # iterator
    		# yield self.x; yield.self.y
    	def __repr__(self):  # for developer
    		class_name = type(self).__name__  # safer to inherit
    		return '{}({!r}, {!r})'.format(class_name, *self)  # iterable
    	def __str__(self):  # for user
    		return str(tuple(self))
    	def __bytes__(self):
    		return (bytes([ord(self.typecode)]) + bytes(array(self.typecode, self)))
    	def __eq__(self, other):
    		# It works for Vector2d operands but also returns True when comparing
    		# Vector2d instances to other iterables holding the same numeric values
    		# (e.g., Vector(3, 4) == [3, 4]).
    		return tuple(self) == tuple(other)
    	def __abs__(self):
    		return math.hypot(self.x, self.y)
    	def __bool__(self):
    		return bool(abs(self))
    	@classmethod
    	def frombytes(cls, octets):
    		# Read the typecode from the first byte.
    		typecode = chr(octets[0])
    		# Create a memoryview from the octets and use the typecode to cast it.
    		memv = memoryview(octets[1:]).cast(typecode)
    		# print(memv)  # <memory at 0x1012fb108>
    		# print(*memv)  # 3.0 4.0
    		return cls(*memv)
    	def __format__(self, fmt_spec=''):
    		if fmt_spec.endswith('p'):
    			fmt_spec = fmt_spec[:-1]
    			outer_fmt = '<{}, {}>'
    		else:
    			outer_fmt = '({}, {})'
    		components = (format(c, fmt_spec) for c in self)
    		return outer_fmt.format(*components)
    	def __hash__(self):
    		return hash(self.x) ^ hash(self.y)
    
    v1 = Vector2d(3, 4)
    print(v1.x)  # 3.0
    # v1.x = 5  # AttributeError: can't set attribute
    a, b = v1  # __iter__
    print(a, b)  # 3.0 4.0
    print(repr(v1))  # Vector2d(3.0, 4.0)
    print(v1)  # (3.0, 4.0) __str__
    print(bytes(v1))  # b'dx00x00x00x00x00x00x08@x00x00x00x00x00x00x10@'
    print(v1 == eval(repr(v1)))  # True  __eq__
    print(abs(v1))  # 5.0
    print(bool(v1))  # True
    print(bool(Vector2d(0, 0)))  # False
    v2 = Vector2d.frombytes(bytes(v1))
    print(v1 == v2)  # True
    print(format(v1))  # (3.0, 4.0)
    print(format(v1, '.3f'))  # (3.000, 4.000)
    print(format(v1, '.2ep'))  # <3.00e+00, 4.00e+00>
    print(hash(v1))  # 7
    
    # 1. In Python 3, __repr__, __str__, and __format__ must always return
    # Unicode strings (type str). Only __bytes__ is supposed to return a
    # byte sequence (type bytes).
    # 2. We can implement the __hash__ method. It should return an int and
    # ideally take into account the hashes of the object attributes that
    # are also used in the __eq__ method, because objects that compare equal
    # should have the same hash. The __hash__ special method documentation
    # suggests using the bitwise XOR operator (^) to mix the hashes of the
    # components.
    # 3. It’s not strictly necessary to implement properties or otherwise
    # protect the instance attributes to create a hashable type. 
    # Implementing __hash__ and __eq__ correctly is all it takes. But the
    # hash value of an instance is never supposed to change.
    

    5. Saving Space with the __slots__ Class Attribute

    P264

    6. Overriding Class Attributes

    • Class attributes can be used as default values for instance attributes.
    • Class attributes are public, they are inherited by subclasses, so it’s common practice to subclass just to customize a class data attribute.
  • 相关阅读:
    CSP-S 2019游记
    南校五天集训游记
    web.xml模板
    JDBC Template的基本使用
    Spring AOP(3)使用AspectJ xml配置
    Spring AOP(2)使用AspectJ注解
    Spring Aop(面向切面编程)
    Spring Bean管理3(xml与注解混合使用)
    Python核心技术与实战——十二|Python的比较与拷贝
    test
  • 原文地址:https://www.cnblogs.com/lb477/p/10945742.html
Copyright © 2020-2023  润新知